#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <assert.h>
#include <unistd.h>

#include <fcntl.h>              /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <asm/types.h>          /* for videodev2.h */

#include <linux/videodev2.h>

#include <libjpeg/jpeglib.h>
#include <libjpeg/jerror.h>
#include <setjmp.h>
#include <pthread.h>

#ifdef __cplusplus
extern "C" {
#endif

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavdevice/avdevice.h>

#include <libavfilter/avfilter.h>
#include <libavfilter/buffersrc.h>
#include <libavfilter/buffersink.h>
//#include <libyuv.h>

using std::string ;
using std::vector ;


#define abs_mcr(x) ((x)>0 ? (x) : -(x))

#define CLEAR(x) memset (&(x), 0, sizeof (x))


#define ERROR_LOCAL -1
#define SUCCESS_LOCAL 0

struct v4l2_markinfo {
    __u32 x;            //x坐标位置
    __u32 y;            //y坐标位置
    __u32 size;            //字体大小
    __u8 content[200];    //水印内容
};

#define VIDIOC_MARK_INFO _IOW('V', BASE_VIDIOC_PRIVATE, struct v4l2_markinfo)

//定义一个缓存结构体
struct buffer {
    void *start;    //空指针
    size_t length;    //长度大小
    size_t buflen;
};

/* for libjpeg */
typedef struct {
    struct jpeg_source_mgr pub;/* public fields */
    int skip;
} memory_source_mgr;
typedef memory_source_mgr *memory_src_ptr;

struct my_error_mgr {
    struct jpeg_error_mgr pub;
    jmp_buf setjmp_buffer;
};

typedef struct my_error_mgr *my_error_ptr;

METHODDEF(void) my_error_exit(j_common_ptr cinfo);
GLOBAL(void) jpeg_memory_src(j_decompress_ptr cinfo, void *data,
                             unsigned long len);
METHODDEF(void) memory_init_source(j_decompress_ptr cinfo);
METHODDEF(boolean) memory_fill_input_buffer(j_decompress_ptr cinfo);
METHODDEF(void) memory_skip_input_data(j_decompress_ptr cinfo, long num_bytes);
METHODDEF(void) memory_term_source(j_decompress_ptr cinfo);
/* end of libjpeg */


class RWLock {
    pthread_rwlock_t _lock;
public:
    RWLock() {
        pthread_rwlock_init(&_lock, NULL);
    }

    int read() {
        return pthread_rwlock_rdlock(&_lock);
    }

    int write() {
        return pthread_rwlock_wrlock(&_lock);
    }

    int unlock() {
        return pthread_rwlock_unlock(&_lock);
    }
};

#define WATERMARK_SIZE    10
struct WaterMarkS {
    string Watermark;
    int MarkX;
    int MarkY;
    int MarkSize;

    //
    RWLock mMarkMtx;

    WaterMarkS() {
        MarkX = 0;
        MarkY = 0;
        MarkSize = 0;
    }
};


class Imageproc {
public:
    Imageproc(void);

    ~Imageproc(void);

public:
    string dev_name;
    int fd;
    buffer *buffers;
    unsigned int n_buffers;

    struct v4l2_capability cap;
    struct v4l2_cropcap cropcap;
    struct v4l2_crop crop;
    struct v4l2_format fmt;
    struct v4l2_streamparm setfps;
    struct v4l2_fmtdesc fmtdesc;
    vector<__u32> v4l2_fmtlist;
    int *rgb;
    buffer readbuffer;

    int errnoexit(const char *s);

    int xioctl(int fd, int request, void *arg);

    int opendevice(string camname);

    int initdevice();

    int getdevice();

    int initmmap();

    int startcapturing();

    int readframeonce();

    int readframe();

    unsigned int convert_yuv_to_rgb_pixel(int y, int u, int v);

    int convert_yuv_to_rgb_buffer(unsigned char *yuv, int *rgb, unsigned int width,
                                  unsigned int height);

    void processimage(const void *p, int l);

    int stopcapturing();

    int uninitdevice();

    int closedevice();

    int setWatermark(int group, char *info);

    int initffmpeg();

    int initfilter(AVCodecContext *pCodecCtx);

    AVCodec *pCodec_MJPEG;
    AVCodecContext *pCodecCtx_MJPEG;
    AVCodecParserContext *pCodecParserCtx_MJPEG;
    AVFrame *pFrame;
    AVFrame *pFrameRGB;
    AVPacket packet;
    SwsContext *img_convert_ctx_MJPEG;
    uint8_t *out_buffer_MJPEG;
    bool ffmpeginit;
    bool substream;

    AVFilterContext *buffersink_ctx;
    AVFilterContext *buffersrc_ctx;
    AVFilterGraph *filter_graph;
    bool filterinit;

    //视频水印
    WaterMarkS mWaterMarkS[WATERMARK_SIZE];

    bool addwatermark(AVFrame *pframe);

    bool addwatermark(uint8_t *pframe);

    int setWatermark(int index, string params, int x, int y, int s);

    int width;
    int height;
};


#ifdef __cplusplus
}
#endif